package org.shj.thread.book2.chapter01;

/**
 * 本例中 Gate 是线程不安全的类。 因为多个线程执行 pass 方法时，name 和 address 的赋值语句有可能是交替
 * 执行的。 线程 A 改变了 name 值后， address 可能被线程 B 赋值。
 * 在其 pass 和 toString 两个方法都加上 synchronized 后，才是线程安全的。
 *
 * @author Shen Huang Jian
 */
public class Main {

	public static void main(String[] args){
		Gate gate = new Gate();
		new UserThread(gate, "Alice", "Alaska").start();
		new UserThread(gate, "Bobby", "Brazil").start();
		new UserThread(gate, "Chris", "Canada").start();
	}

	static class Gate{
		private int counter = 0;
		private String name = "Nobody";
		private String address = "Nowhere";

		public void pass(String name, String address){
			this.counter++;
			this.name = name;
		/*try {
			Thread.sleep(50);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}*/
			this.address = address;
			check();
		}

		public String toString(){
			return "No." + counter + ":" + name + ", " + address;
		}

		/**
		 * 从代码来看，name 和 address 是在同一个方法里被赋值的，它们的首字母应该是相等的，
		 * 但是从运行结果看，它们有可能不等。这是因为： 在多线程环境下，这种赋值方式是不安全的。
		 */
		private void check(){
			if(name.charAt(0) != address.charAt(0)){
				System.out.println("********** broken *****" + toString());
				System.exit(-1);
			}
		}
	}

	static class UserThread extends Thread{
		private final Gate gate;
		private final String myName;
		private final String myAddress;

		public UserThread(Gate gate, String myName, String myAddress){
			this.gate = gate;
			this.myAddress = myAddress;
			this.myName = myName;
		}

		public void run(){
			System.out.println(myName + " BEGIN...");
			while(true){
				gate.pass(myName, myAddress);
			}
		}
	}
}




